# -*- coding: utf-8 -*-
# @Author: Jerry
# @Date:   2022-03-09 14:33:59
# @Last Modified by:   Jerry
# @Last Modified time: 2022-03-09 15:47:06

# **********
# OpenCV中的图像处理 » 4_10_3_直方图3：二维直方图
# http://www.woshicver.com

# **********
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
import os
rootpath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
datapath = os.path.join(rootpath,'data')
imgpath = lambda name: os.path.join(datapath,name)

# **********
'''目标
学习查找和绘制2D直方图。
示例（samples_python / color_histogram.py）用于查找颜色直方图

介绍
在第一篇文章中，我们计算并绘制了一维直方图。
之所以称为一维，是因为我们仅考虑一个特征，即像素的灰度强度值。

但是在二维直方图中，您要考虑两个特征。 通常，它用于查找颜色直方图，
其中两个特征是每个像素的 色相 和 饱和度 值。 hsv '''


# **********
'''OpenCV中的二维直方图
它非常简单，并且使用相同的函数 cv.calcHist()进行计算。
对于颜色直方图，我们需要将图像从BGR转换为HSV。
（请记住，对于一维直方图，我们从BGR转换为灰度）。

对于二维直方图，cv.calcHist()的参数将进行如下修改：
channel = [0,1]，因为我们需要同时处理H和S平面。
bins = [180,256] 对于H平面为180，对于S平面为256。
range = [0,180,0,256] 色相值介于0和180之间，饱和度介于0和256之间。'''

src = cv.imread(imgpath('home.jpg'))
hsv = cv.cvtColor(src,cv.COLOR_BGR2HSV)
hist_cv = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
# cv.imshow('hist',hist_cv)


# **********
'''Numpy中的二维直方图
Numpy还为此提供了一个特定的函数:np.histogram2d()
(记住，对于一维直方图我们使用了np.histogram())'''
h=hsv[:,:,0]
s=hsv[:,:,1]
hist_np, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])
# 第一个参数是H平面，第二个是S平面，第三个是每个箱子的数量，第四个是它们的范围。

# **********
# 绘制二维直方图
# 可以使用**cv.imshow**()函数像平常一样显示它们。
# 它将是一幅灰度图像，除非您知道不同颜色的色相值，否则不会对其中的颜色有太多了解。
# cv.imshow('cv hist',hist_cv)

# 可以使用matplotlib.pyplot.imshow()函数绘制具有不同颜色图的2D直方图。
# 它使我们对不同的像素密度有了更好的了解。
# 但是，除非您知道不同颜色的色相值，否则乍一看并不能使我们知道到底是什么颜色。

# plt.imshow(hist_cv,interpolation='nearest') # 使用此功能时，插值法应采用最近邻以获得更好的结果。
# plt.show()


# **********
# color_histogram.py
class App():
    def set_scale(self, val):
        self.hist_scale = val

    def run(self):
        hsv_map = np.zeros((180, 256, 3), np.uint8)
        h, s = np.indices(hsv_map.shape[:2])
        hsv_map[:,:,0] = h
        hsv_map[:,:,1] = s
        hsv_map[:,:,2] = 255 # 在HSV中创建了一个颜色图
        hsv_map = cv.cvtColor(hsv_map, cv.COLOR_HSV2BGR) # 将其转换为BGR
        cv.imshow('hsv_map', hsv_map)

        cv.namedWindow('hist', 0)
        self.hist_scale = 10

        cv.createTrackbar('scale', 'hist', self.hist_scale, 32, self.set_scale)

        frame = cv.imread(imgpath('home.jpg'))
        cv.imshow('camera', frame)

        small = cv.pyrDown(frame)

        hsv = cv.cvtColor(small, cv.COLOR_BGR2HSV)
        dark = hsv[...,2] < 32
        hsv[dark] = 0
        h = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])

        h = np.clip(h*0.005*self.hist_scale, 0, 1)
        vis = hsv_map*h[:,:,np.newaxis] / 255.0 # 将所得的直方图图像与此颜色图相乘
        cv.imshow('hist', vis)

        # ch = cv.waitKey(1)
        print('Done')

App().run()
cv.waitKey(0)

